package com.example.medispider.service.detail;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.read.listener.ReadListener;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.example.medispider.pojo.detail.detail.SettlementDetail;
import com.example.medispider.pojo.detail.userinfo.BriefUserInfo;
import com.example.medispider.service.listener.MediSpiderListener;
import com.example.medispider.service.pipeline.ExcelPipeline;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import us.codecraft.webmagic.Request;
import us.codecraft.webmagic.Spider;
import us.codecraft.webmagic.SpiderListener;
import us.codecraft.webmagic.model.HttpRequestBody;
import us.codecraft.webmagic.utils.HttpConstant;

import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class DetailDataExecutor {
    private static final String REQUEST_URL = "https://portal.hub.hsip.gov.cn/mbs-dy-420500/web/multisearch/settleAccount/querySetlDDTOList";
    private static final String FRONT_URL = "https://portal.hub.hsip.gov.cn/mbs/mbs-dy-420500-ui/N1407.html#/N140701";
    private final DetailPageProcessor detailPageProcessor;
    private final List<SpiderListener> mediSpiderListeners = new ArrayList<>();
    private String outputFilePath;
    private String masterFilePath;
    private String errorFilePath;
    private int threadNum = 10;
    /**
     * 分页大小
     */
    private int pageSize = 100; //默认100

    @Autowired
    public DetailDataExecutor(DetailPageProcessor detailPageProcessor, MediSpiderListener mediSpiderListener) {
        this.detailPageProcessor = detailPageProcessor;
        this.mediSpiderListeners.add(mediSpiderListener);

    }

    public void run() {
        // 创建 Pipeline
        ExcelPipeline<SettlementDetail> detailPipeline = new ExcelPipeline<>(outputFilePath, errorFilePath, SettlementDetail.class);
        // 创建Spider
        Spider spider = Spider.create(detailPageProcessor.setPageSize(pageSize))
                .addPipeline(detailPipeline)
                .setSpiderListeners(mediSpiderListeners)
                .thread(threadNum);
        // 读取结算主单，根据结算主单爬取结算明细
        try {
            EasyExcel.read(masterFilePath, BriefUserInfo.class, new ReadListener<BriefUserInfo>() {
                private final ArrayList<Request> cacheRequests = new ArrayList<>();
                private final int BATCH_COUNT = 100;  //缓存大小
                private int count = 0;                        //结算数据量

                @Override
                public void invoke(BriefUserInfo briefUserInfo, AnalysisContext context) {
                    // 创建 Request 对象
                    Request request = createRequest(briefUserInfo);
                    cacheRequests.add(request);
                    count++;
                    if (cacheRequests.size() >= BATCH_COUNT) {
                        spider.addRequest(cacheRequests.toArray(new Request[0])).run();
                        cacheRequests.clear();
                    }
                }

                @Override
                public void doAfterAllAnalysed(AnalysisContext context) {
                    if (!cacheRequests.isEmpty()) {
                        spider.addRequest(cacheRequests.toArray(new Request[0])).run();
                    }
                    System.out.println("结算主单读取完毕，共计" + count + "条结算主单数据");
                }
            }).excelType(ExcelTypeEnum.CSV).sheet(0).doRead();
        } catch (Exception e) {
            System.err.println("爬取结算明细时出错：" + e.getMessage());
        } finally {
            //关闭Pipeline
            detailPipeline.close();
        }
    }


    /**
     * 根据人员编号和结算ID创建 Request
     *
     * @return Request
     */
    private Request createRequest(BriefUserInfo briefUserInfo) {
        // 创建 Request 对象
        Request request = new Request(REQUEST_URL);
        request.setMethod(HttpConstant.Method.POST); // 设置请求方法为 POST
        // 准备 POST 参数（以表单格式为例）
        Map<String, Object> params = new HashMap<>();
        params.put("pageNum", 1);
        params.put("pageSize", pageSize);
        params.put("psnNo", briefUserInfo.getPsnNo());
        params.put("setlId", briefUserInfo.getSetlId());
        params.put("_modulePartId_", "");
        params.put("frontUrl", FRONT_URL);
        // 将参数设置为表单格式的请求体，并指定编码
        HttpRequestBody httpRequestBody = HttpRequestBody.form(params, StandardCharsets.UTF_8.name());
        request.setRequestBody(httpRequestBody);
        return request;
    }


    public DetailDataExecutor setPageSize(int pageSize) {
        this.pageSize = pageSize;
        return this;
    }

    public DetailDataExecutor setOutputFilePath(String outputFilePath) {
        this.outputFilePath = outputFilePath;
        return this;
    }

    public DetailDataExecutor setMasterFilePath(String masterFilePath) {
        this.masterFilePath = masterFilePath;
        return this;
    }

    public DetailDataExecutor setErrorFilePath(String errorFilePath) {
        this.errorFilePath = errorFilePath;
        return this;
    }

    public DetailDataExecutor setThreadNum(int threadNum) {
        this.threadNum = threadNum;
        return this;
    }
}
